﻿using System;
using System.Collections.Generic;
using System.Windows.Browser;

namespace com.bodurov.NearestStarsVisualizer
{
    public class StarDatabase
    {
        private readonly List<StarInfo> _stars = new List<StarInfo>();
        private readonly Dictionary<int, StarInfo> _starsDict = new Dictionary<int, StarInfo>();
        private readonly List<KeyValuePair<StarInfo, StarInfo>> _lines = new List<KeyValuePair<StarInfo, StarInfo>>();

        public StarDatabase()
        {
            this.MinAbsoluteMagnitude = Double.MaxValue;
            this.MaxAbsoluteMagnitude = Double.MinValue;
        }

        public void AddStarInfo(StarInfo info)
        {
            this._stars.Add(info);
            this._starsDict.Add(info.ID, info);
        }

        public List<StarInfo> Stars { get { return this._stars; } }
        public List<KeyValuePair<StarInfo, StarInfo>> Lines { get { return this._lines; } }

        public void StarsAdded()
        {
            foreach (var starInfo in this.Stars)
            {
                if (!starInfo.IsNearStar) continue;

                CalculateAbsoluteMagnitude(starInfo);

                if (starInfo.ApparentMagnitude < 6 && starInfo.ApparentMagnitude > -2)
                    CalculateApparentMagnitude(starInfo);

                CalculateDisatnce(starInfo);



            }
        }

        private void CalculateApparentMagnitude(StarInfo starInfo)
        {
            var appMag = starInfo.ApparentMagnitude;

            if (appMag == null)
            {
                throw new Exception("Apparent Magnitude for star ID=" + starInfo.ID + " must not be null");
            }

            if (this.MinApparentMagnitude > appMag)
                this.MinApparentMagnitude = appMag ?? 0;
            if (this.MaxApparentMagnitude < appMag)
                this.MaxApparentMagnitude = appMag ?? 0;
        }

        private void CalculateDisatnce(StarInfo starInfo)
        {
            var distance = starInfo.DistanceLightYears;

            if (distance == null)
            {
                throw new Exception("Distance for star ID=" + starInfo.ID + " must not be null");
            }

            if (this.MinDistance > distance)
                this.MinDistance = distance ?? 0;
            if (this.MaxDistance < distance)
                this.MaxDistance = distance ?? 0;
        }

        private void CalculateAbsoluteMagnitude(StarInfo starInfo)
        {

            var absMag = starInfo.AbsoluteMagnitude;

            if (absMag == null)
            {
                throw new Exception("Absolute Magnitude for star ID=" + starInfo.ID + " must not be null");
            }

            if (this.MinAbsoluteMagnitude > absMag)
                this.MinAbsoluteMagnitude = absMag ?? 0;
            if (this.MaxAbsoluteMagnitude < absMag)
                this.MaxAbsoluteMagnitude = absMag ?? 0;
        }

        public double MinAbsoluteMagnitude { get; private set; }
        public double MaxAbsoluteMagnitude { get; private set; }

        public double MinApparentMagnitude { get; private set; }
        public double MaxApparentMagnitude { get; private set; }
        
        public double MinDistance { get; private set; }
        public double MaxDistance { get; private set; }

        public double GetAbsoluteMagnitudeCoef(StarInfo starInfo)
        {
            return GetCoef(this.MinAbsoluteMagnitude, this.MaxAbsoluteMagnitude, starInfo.AbsoluteMagnitude ?? 0);
        }

        public double GetApparentMagnitudeCoef(StarInfo starInfo)
        {
            return GetCoef(this.MinApparentMagnitude, this.MaxApparentMagnitude, starInfo.ApparentMagnitude ?? 0);
        }

        public double GetDistanceCoef(StarInfo starInfo)
        {
            return GetCoef(this.MinDistance, this.MaxDistance, starInfo.DistanceLightYears ?? 0);
        }

        private static double GetCoef(double min, double max, double curr)
        {
            var range100 = Math.Abs(max - min);
            var rangecurr = Math.Abs(max - curr);

            return rangecurr / range100;
        }

        public void AddLine(int fromID, int toID)
        {
            StarInfo from;
            StarInfo to;
            if (this._starsDict.TryGetValue(fromID, out from) && this._starsDict.TryGetValue(toID, out to))
            {
                this._lines.Add(new KeyValuePair<StarInfo, StarInfo>(from, to));
            }
        }
    }
}
